#include "preHeader.h"
#include "Session/GameSession.h"
#include "Session/GameSessionHandler.h"
#include "SQLHelper.h"

int GameSessionHandler::HandleLoadAllPlayerCharacterInfo(GameSession *pSession, INetPacket &pck, const RPCSession::RequestMetaInfo &info)
{
	auto LoadAllPlayerCharacterInfo = [GSRPCAsyncTaskArgs]() {
		TNetBuffer<65536> buffer;
		size_t n = 0;
		auto connPtr = sMysqlDatabasePool.GetCharDB()->GetConnAutoPtr();
		if (connPtr) {
			uint32 lastInstID = 0;
			auto sqlFormat = CreateSQL4SelectEntity<InstPlayerOutlineInfo>(
				"ipcInstID>%u AND ipcDeleteTime=0 ORDER BY ipcInstID");
mark:		auto rst = connPtr->FastQueryFormat(sqlFormat.c_str(), lastInstID);
			if (rst) {
				while (rst.NextRow()) {
					auto row = rst.Fetch();
					auto instInfo = LoadEntityFromMysqlRow<InstPlayerOutlineInfo>(row);
					SaveToINetStream(instInfo, buffer);
					lastInstID = instInfo.ipcInstID;
					if (++n % 250 == 0) {
						GameSession::Feedback(gsPtr, buffer, info.sn, RPCErrorNone, false);
						buffer.Clear();
					}
				}
				if (connPtr->GetLastErrno() == 0) {
					GameSession::Feedback(gsPtr, buffer, info.sn, RPCErrorNone, true);
				} else {
					goto mark;
				}
			} else {
				GameSession::FeedbackError(gsPtr, info.sn, DBPErrorQueryMysqlFailed);
			}
		} else {
			GameSession::FeedbackError(gsPtr, info.sn, DBPErrorConnectMysqlFailed);
		}
	};
	sDeferAsyncTaskMgr.AddTask(CreateAsyncTask(LoadAllPlayerCharacterInfo));
	return SessionHandleCapture;
}

int GameSessionHandler::HandleLoadAccountPlayerPreviewInfo(GameSession *pSession, INetPacket &pck, const RPCSession::RequestMetaInfo &info)
{
	auto LoadAccountPlayerPreviewInfo = [GSRPCAsyncTaskArgs]() {
		TNetBuffer<65536> buffer;
		auto ipcAcctID = pckPtr->Read<uint32>();
		auto connPtr = sMysqlDatabasePool.GetCharDB()->GetConnAutoPtr();
		if (connPtr) {
			auto sqlFormat = CreateSQL4SelectEntity<InstPlayerPreviewInfo>(
				"ipcAcctID=%u AND ipcDeleteTime=0");
			auto rst = connPtr->QueryFormat(sqlFormat.c_str(), ipcAcctID);
			if (rst) {
				while (rst.NextRow()) {
					auto row = rst.Fetch();
					auto instInfo = LoadEntityFromMysqlRow<InstPlayerPreviewInfo>(row);
					SaveToINetStream(instInfo, buffer);
				}
				GameSession::Feedback(gsPtr, buffer, info.sn);
			} else {
				GameSession::FeedbackError(gsPtr, info.sn, DBPErrorQueryMysqlFailed);
			}
		} else {
			GameSession::FeedbackError(gsPtr, info.sn, DBPErrorConnectMysqlFailed);
		}
	};
	sAsyncTaskMgr.AddTask(CreateAsyncTask(LoadAccountPlayerPreviewInfo));
	return SessionHandleCapture;
}

int GameSessionHandler::HandleLoadOnePlayerCharacterInfo(GameSession *pSession, INetPacket &pck, const RPCSession::RequestMetaInfo &info)
{
	auto LoadOnePlayerCharacterInfo = [GSRPCAsyncTaskArgs]() {
		TNetBuffer<65536> buffer;
		auto ipcInstID = pckPtr->Read<uint32>();
		auto connPtr = sMysqlDatabasePool.GetCharDB()->GetConnAutoPtr();
		if (connPtr) {
			auto sqlFormat = CreateSQL4SelectEntity<InstPlayerOutlineInfo>(
				"ipcInstID=%u AND ipcDeleteTime=0");
			auto rst = connPtr->QueryFormat(sqlFormat.c_str(), ipcInstID);
			if (rst) {
				if (rst.NextRow()) {
					auto row = rst.Fetch();
					auto instInfo = LoadEntityFromMysqlRow<InstPlayerOutlineInfo>(row);
					SaveToINetStream(instInfo, buffer);
				}
				GameSession::Feedback(gsPtr, buffer, info.sn);
			} else {
				GameSession::FeedbackError(gsPtr, info.sn, DBPErrorQueryMysqlFailed);
			}
		} else {
			GameSession::FeedbackError(gsPtr, info.sn, DBPErrorConnectMysqlFailed);
		}
	};
	sAsyncTaskMgr.AddTask(CreateAsyncTask(LoadOnePlayerCharacterInfo));
	return SessionHandleCapture;
}

int GameSessionHandler::HandleNewOnePlayerInstance(GameSession *pSession, INetPacket &pck, const RPCSession::RequestMetaInfo &info)
{
	auto NewOnePlayerInstance = [GSRPCAsyncTaskArgs]() {
		NetBuffer buffer;
		inst_player_char instInfo;
		LoadFromINetStream(instInfo, *pckPtr);
		auto connPtr = sMysqlDatabasePool.GetCharDB()->GetConnAutoPtr();
		if (connPtr) {
			auto sqlStr = CreateSQL4InsertEntity(instInfo);
			auto rst = connPtr->Execute(sqlStr.c_str());
			if (rst.second) {
				buffer << (u32)connPtr->GetInsertID();
				GameSession::Feedback(gsPtr, buffer, info.sn);
			} else {
				GameSession::FeedbackError(gsPtr, info.sn, DBPErrorInsertMysqlFailed);
			}
		} else {
			GameSession::FeedbackError(gsPtr, info.sn, DBPErrorConnectMysqlFailed);
		}
	};
	sAsyncTaskMgr.AddTask(CreateAsyncTask(NewOnePlayerInstance));
	return SessionHandleCapture;
}

static std::string CreateSQL4UpdatePlayerInstance(const inst_player_char& instInfo)
{
	static const ssize_t ingoreFieldIndexs[] = {
		GetTableFieldIndexByName<inst_player_char>("ipcInstID"),
		GetTableFieldIndexByName<inst_player_char>("ipcAcctID"),
		GetTableFieldIndexByName<inst_player_char>("ipcNickName"),
		GetTableFieldIndexByName<inst_player_char>("ipcDeleteTime"),
		GetTableFieldIndexByName<inst_player_char>("ipcGsWriteValue"),
	};
	std::ostringstream s;
	s << "UPDATE `" << GetTableName<inst_player_char>() << "` SET ";
	for (size_t i = 0, n = GetTableFieldNumber<inst_player_char>(); i < n; ++i) {
		if (IS_ARRAY_CONTAIN_VALUE(ingoreFieldIndexs, i)) { continue; }
		auto name = GetTableFieldNameByIndex<inst_player_char>(i);
		auto value = GetTableFieldValue(instInfo, i);
		s << "`" << name << "`='" << SQL_ESCAPE_STRING(value) << "',";
	}
	s.seekp(-1, std::ios::cur) << " WHERE ipcInstID=" << instInfo.ipcInstID;
	return s.str();
}

int GameSessionHandler::HandleSaveOnePlayerInstance(GameSession *pSession, INetPacket &pck, const RPCSession::RequestMetaInfo &info)
{
	auto SaveOnePlayerInstance = [GSRPCAsyncTaskArgs]() {
		NetBuffer buffer;
		inst_player_char instInfo;
		LoadFromINetStream(instInfo, *pckPtr);
		auto connPtr = sMysqlDatabasePool.GetCharDB()->GetConnAutoPtr();
		if (connPtr) {
			auto sqlStr = CreateSQL4UpdatePlayerInstance(instInfo);
			auto rst = connPtr->Execute(sqlStr.c_str());
			if (rst.second) {
				buffer << (u32)rst.first;
				GameSession::Feedback(gsPtr, buffer, info.sn);
			} else {
				GameSession::FeedbackError(gsPtr, info.sn, DBPErrorUpdateMysqlFailed);
			}
		} else {
			GameSession::FeedbackError(gsPtr, info.sn, DBPErrorConnectMysqlFailed);
		}
	};
	sAsyncTaskMgr.AddTask(CreateAsyncTask(SaveOnePlayerInstance));
	return SessionHandleCapture;
}

int GameSessionHandler::HandleLoadOnePlayerInstance(GameSession *pSession, INetPacket &pck, const RPCSession::RequestMetaInfo &info)
{
	auto LoadOnePlayerInstance = [GSRPCAsyncTaskArgs]() {
		TNetBuffer<65536> buffer;
		auto ipcInstID = pckPtr->Read<uint32>();
		auto connPtr = sMysqlDatabasePool.GetCharDB()->GetConnAutoPtr();
		if (connPtr) {
			auto sqlFormat = CreateSQL4SelectEntity<inst_player_char>(
				"ipcInstID=%u AND ipcDeleteTime=0");
			auto rst = connPtr->QueryFormat(sqlFormat.c_str(), ipcInstID);
			if (rst) {
				if (rst.NextRow()) {
					auto row = rst.Fetch();
					auto instInfo = LoadEntityFromMysqlRow<inst_player_char>(row);
					SaveToINetStream(instInfo, buffer);
				}
				GameSession::Feedback(gsPtr, buffer, info.sn);
			} else {
				GameSession::FeedbackError(gsPtr, info.sn, DBPErrorQueryMysqlFailed);
			}
		} else {
			GameSession::FeedbackError(gsPtr, info.sn, DBPErrorConnectMysqlFailed);
		}
	};
	sAsyncTaskMgr.AddTask(CreateAsyncTask(LoadOnePlayerInstance));
	return SessionHandleCapture;
}

int GameSessionHandler::HandleDeleteOnePlayerInstance(GameSession *pSession, INetPacket &pck, const RPCSession::RequestMetaInfo &info)
{
	auto DeleteOnePlayerInstance = [GSRPCAsyncTaskArgs]() {
		NetBuffer buffer;
		auto playerId = pckPtr->Read<uint32>();
		auto connPtr = sMysqlDatabasePool.GetCharDB()->GetConnAutoPtr();
		if (connPtr) {
			auto sqlFormat = "UPDATE `%s` SET ipcNickName=CONCAT_WS(',',"
				"ipcNickName,ipcInstID),ipcDeleteTime=%lld WHERE ipcInstID=%u";
			auto rst = connPtr->ExecuteFormat(sqlFormat,
				GetTableName<inst_player_char>(), (s64)GET_UNIX_TIME, playerId);
			if (rst.second) {
				buffer << playerId << (u32)rst.first;
				GameSession::Feedback(gsPtr, buffer, info.sn);
			} else {
				GameSession::FeedbackError(gsPtr, info.sn, DBPErrorDeleteMysqlFailed);
			}
		} else {
			GameSession::FeedbackError(gsPtr, info.sn, DBPErrorConnectMysqlFailed);
		}
	};
	sAsyncTaskMgr.AddTask(CreateAsyncTask(DeleteOnePlayerInstance));
	return SessionHandleCapture;
}

int GameSessionHandler::HandleSaveMultiPlayerGsInfo(GameSession *pSession, INetPacket &pck, const RPCSession::RequestMetaInfo &info)
{
	return SessionHandleSuccess;
}
